<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <title>文档</title>
  
  <link href="../css/semantic/semantic.min.css" rel="stylesheet">
  <link href="../css/markdown.css" rel="stylesheet">
  <link href="../css/wtxynavigation.css" rel="stylesheet">
  <script src="../js/jquery.min.js"></script>
  <script type="text/javascript" src="../js/include.js"></script>
  
  <style>
    body{padding-top:0;background:#f7f7f7}
    body>.ui.container{width:100%;padding:0}
    #project-title{background:#6e6e6e;width:100%;line-height:3.572rem;color:#fff;font-size:1.2rem}
    #project-title .title-wrap{font-weight:700;padding:0 12px;width:100%;max-width:1366px!important;min-width:900px;margin:0 auto}
    #project-title .left,#project-title right{display:inline-block}
    #project-title .right{float:right}
    #project-title .right .wiki-actions .menu{left:auto;right:0;margin-top:.4em!important}
    #wiki-preview-container{width:100%;max-width:1366px!important;min-width:900px;padding:0;border:1px solid #e3e9ed;border-top:0}
    #wiki-preview>.ui.segment{margin-top:0;padding:1rem;padding-left:0;border:0}
    .hover-places{display:inline-block}
    #page-detail{width:60%;margin:0 auto}
    #page-detail .title{font-weight:700;font-size:24px;padding:12px 0;border-bottom:1px solid #ccc}
    #page-detail .content{margin-top:15px}
    .content p{word-wrap:break-word}
    #wiki-parent,#wiki-title,#wikis{display:none}
    .ui.grid{padding:0!important}
    #ex-all{cursor:pointer;color:#537c8d}
  </style>
</head>
<body>
  <div class="ui container">
    <div id="project-title">
      <div class="title-wrap">
        <div class="left">
          <i class="icon eye"></i>
          文档预览:
          mianmSDK
        </div>
        <div class="right">
          Export by Gitee
        </div>
      </div>
    </div>

    <div class="ui container" id="wiki-preview-container">
      <div id="wiki-preview">
        <div class="ui segment">
          <div id="page-detail" class="markdown-body">
            <div class='title'>33.runloop事件循环机制</div><div class='content'><h1>
<a id="runloop事件循环机制" class="anchor" href="#runloop%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF%E6%9C%BA%E5%88%B6"></a>runloop事件循环机制</h1>
<p><strong>关键词</strong>:<code>事件循环机制</code>,<code>runloop</code>,<code>UIApplicationMain</code>,<code>Source</code>,<code>mach_msg</code>,<code>mach port</code></p>
<p>最后都会调用到<code>void CFRunLoopRun()</code>,</p>
<h2>
<a id="描述" class="anchor" href="#%E6%8F%8F%E8%BF%B0"></a>描述</h2>
<ol>
<li>
<code>runloop</code>启动之后首先会发送一个通知, 告知观察者当前<code>runloop</code>将启动</li>
<li>发送通知说: 将要处理<strong>Timer/Source0</strong>事件</li>
<li>正式处理<strong>Source0</strong>事件</li>
<li>如果需要有<strong>Source1</strong>要处理,就通过一条goto语句来进行一个代码逻辑的跳转台转到<strong>8</strong>
</li>
<li>没有<strong>Source1</strong>要处理的话, 线程就将要休眠</li>
<li>然后就是<strong>用户态</strong>到<strong>内核态</strong>的切换, 就正式休眠,等待唤醒了</li>
<li>发送通知说: 线程被唤醒了</li>
<li>跳转到<strong>2</strong>: 处理唤醒时收到的消息</li>
<li>最后我们杀死APP的时候就产生一个<strong>runloop</strong>的退出</li>
</ol>
<p><img src="images/runlooprun01.png" alt="runlooprun01"></p>
<h1>
<a id="runloop核心" class="anchor" href="#runloop%E6%A0%B8%E5%BF%83"></a>runloop核心</h1>
<ol>
<li>
<code>main</code>函数经过一系列处理之后, 最终会调用一个系统函数<code>mach_msg()</code>
</li>
<li>于是就发生了一个<strong>系统调用</strong>
</li>
<li>经过系统调用了以后呢, 实际上呢当前线程就把控制权转交给<strong>核心态</strong>(<strong>内核态</strong>)</li>
<li>然后呢<code>mach_msg()</code>在一定条件下会返回给调用方,<strong>内核态</strong> ---&gt; <strong>用户态</strong>
</li>
<li>触发返回的逻辑呢, 就是<strong>唤醒线程的逻辑</strong>, 比如说我们收到了一个<code>Source1</code>或者<strong>Timer</strong>事件回调,或者<strong>外部手动的唤醒</strong>
</li>
<li>当前APP主运行循环(<code>runloop</code>)就会被唤醒</li>
</ol>
<p><img src="images/runlooprun02.png" alt="runlooprun02"></p>
<h1>
<a id="问一个处于休眠状态的runloop我们可以通过哪些方式唤醒它" class="anchor" href="#%E9%97%AE%E4%B8%80%E4%B8%AA%E5%A4%84%E4%BA%8E%E4%BC%91%E7%9C%A0%E7%8A%B6%E6%80%81%E7%9A%84runloop%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%93%AA%E4%BA%9B%E6%96%B9%E5%BC%8F%E5%94%A4%E9%86%92%E5%AE%83"></a>问一个处于休眠状态的runloop我们可以通过哪些方式唤醒它?</h1>
<h1>
<a id="答" class="anchor" href="#%E7%AD%94"></a>答:</h1>
<ol>
<li><strong>Source1</strong></li>
<li><strong>Timer事件回调</strong></li>
<li><strong>外部手动唤醒</strong></li>
</ol>
<h1>
<a id="问我们点击了app图标到程序启动运行然后到最终退出系统都发生了什么了" class="anchor" href="#%E9%97%AE%E6%88%91%E4%BB%AC%E7%82%B9%E5%87%BB%E4%BA%86app%E5%9B%BE%E6%A0%87%E5%88%B0%E7%A8%8B%E5%BA%8F%E5%90%AF%E5%8A%A8%E8%BF%90%E8%A1%8C%E7%84%B6%E5%90%8E%E5%88%B0%E6%9C%80%E7%BB%88%E9%80%80%E5%87%BA%E7%B3%BB%E7%BB%9F%E9%83%BD%E5%8F%91%E7%94%9F%E4%BA%86%E4%BB%80%E4%B9%88%E4%BA%86"></a>问我们点击了APP图标,到程序启动,运行,然后到最终退出,系统都发生了什么了?</h1>
<h1>
<a id="答-1" class="anchor" href="#%E7%AD%94-1"></a>答:</h1>
<ol>
<li>首先入口是<strong>main</strong>函数,</li>
<li>然后<strong>main</strong>函数调用了<code>UIApplicationMain</code>函数</li>
<li>
<code>UIApplicationMain</code>函数内部会启动主线程的<code>runloop</code>
</li>
<li>经过一系列的处理然后进入,休眠状态</li>
<li>然后这个时候你点击一下屏幕, 就会产生一个<code>mach port</code>
</li>
<li>然后基于<code>mach port</code>最终转成一个<code>Source1</code>, 然后唤醒主线程</li>
<li>最后我们杀死APP的时候就产生一个<strong>runloop</strong>的退出</li>
<li>
<strong>runloop</strong>退出之后呢,线程也就销毁掉了</li>
</ol></div>
          </div>
        </div>
      </div>
      </div>
  </div>
</body>
</html>